home *** CD-ROM | disk | FTP | other *** search
- /*
- File: Hardware.c
-
- Contains: Routines for dealing with virtual sound hardware from a 'sdev' component.
-
- Written by: Mark Cookson--based on code by Kip Olson
-
- Copyright: Copyright © 1993-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 8/16/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
-
-
- */
-
- #ifndef __HARDWARE__
- #include "Hardware.h"
- #endif
- #include <Devices.h>
- #define DEBUG false
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Initialize the hardware.
-
- OSErr SetupHardware(SoundComponentGlobalsPtr globals) {
- HardwareGlobalsPtr hwGlobals = globals->hwGlobals;
- unsigned long samples;
- OSErr result = noErr;
-
- #if DEBUG
- DebugStr ("\pIn SetupHardware");
- #endif
-
- // Setup hardware here. This example just calculates the interrupt interval
- // for the time manager task interrupt based on the current sample rate.
-
- globals->interruptInterval = UnsignedFixedMulDiv(((long)kHardwareBufferSize) << 16, 1000000, hwGlobals->sampleRate);
-
- samples = UnsignedFixedMulDiv(hwGlobals->sampleRate, kSecondsInIOBuffer, kFix1);
- samples *= (hwGlobals->sampleSize >> 3) * hwGlobals->numChannels;
- globals->ioBufferSize = (samples + kHardwareBufferSize - 1) & (~(kHardwareBufferSize - 1));
-
- globals->thisSifter.flags = 0;
- globals->thisSifter.format = (hwGlobals->sampleSize == 8) ? kOffsetBinary : kTwosComplement; // set to hardware defaults
- globals->thisSifter.sampleRate = hwGlobals->sampleRate;
- globals->thisSifter.sampleSize = hwGlobals->sampleSize;
- globals->thisSifter.numChannels = hwGlobals->numChannels;
- globals->thisSifter.sampleCount = hwGlobals->bufferSize;
-
- if (globals->hwGlobals->outputToFile) {
- result = SetupOutputFile(globals); // initialize output file
- }
-
- #if DEBUG
- if (result != noErr) {
- DebugStr ("\pGot an error in SetupHardware");
- }
- #endif
-
- return (result);
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Release the hardware.
- //BUG ALERT! If we sample MicroSeconds at just the wrong time, we could be here for a long time!
- void ReleaseHardware(SoundComponentGlobalsPtr globals) {
- unsigned long timeLimit, startTime;
-
- #if DEBUG
- DebugStr ("\pIn ReleaseHardware");
- #endif
-
- startTime = MicroSeconds();
- timeLimit = globals->interruptInterval << 1; // wait for 2 interrupt periods
- while ((globals->hardwareOn) && // wait until interrupts turn off
- ((MicroSeconds() - startTime) < timeLimit)) { // or we time out
- ;
- }
-
- StopHardware(globals); // make sure hardware is off
-
- if (globals->fRefNum) {
- CloseOutputFile(globals); // close output file
- globals->fRefNum = 0;
- }
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Turn on hardware interrupts.
-
- void StartHardware(SoundComponentGlobalsPtr globals) {
- #if DEBUG
- DebugStr ("\pIn StartHardware");
- #endif
-
- if (!globals->hardwareOn) {
- globals->hardwareOn = true; // the hardware will soon be on
-
- // Turn hardware on here. The example uses the time manager for interrupts
-
- #ifndef FakeInterrupts
- // start the time manager task going
-
- globals->tmTask.task.tmAddr = NewTimerProc (TMInterrupt);
- globals->tmTask.task.tmCount = 0;
- globals->tmTask.task.tmWakeUp = 0;
- globals->tmTask.task.tmReserved = 0;
- globals->tmTask.globals = globals;
-
- InsXTime((QElemPtr) &globals->tmTask);
- PrimeTime((QElemPtr) &globals->tmTask, -globals->interruptInterval);
- #endif
- }
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Turn off hardware interrupts.
-
- void StopHardware(SoundComponentGlobalsPtr globals) {
- #if DEBUG
- DebugStr ("\pIn StopHardware");
- #endif
-
- if (globals->hardwareOn) {
- // Turn hardware off here. The example removes the time manager task
-
- #ifndef FakeInterrupts
- //Dispose of the Time Manager task UPP made in StartHardware
- RmvTime((QElemPtr) &globals->tmTask);
- DisposeRoutineDescriptor (globals->tmTask.task.tmAddr);
- #endif
- globals->hardwareOn = false; // the hardware is now off
- }
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Temporarily suspend hardware interrupts, so the interrupt routine can work in peace.
-
- void SuspendHardware(SoundComponentGlobalsPtr globals) {
- #if DEBUG
- DebugStr ("\pIn SuspendHardware");
- #endif
-
- if (globals->hardwareOn) {
- // Suspend hardware interrupts here
- }
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Resume hardware interrupts after they were suspended.
-
- void ResumeHardware(SoundComponentGlobalsPtr globals) {
- #if DEBUG
- DebugStr ("\pIn ResumeHardware");
- #endif
-
- if (globals->hardwareOn) {
- // Resume hardware interrupts here. The example queues another time manager interrupt
-
- #ifndef FakeInterrupts
- PrimeTime((QElemPtr) &globals->tmTask, -globals->interruptInterval);
- #endif
- }
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Copy samples to the hardware buffer. In our case, write to a file.
-
- #define SamplesToBytes(samples, shift) (samples << shift)
- #define BytesToSamples(bytes, shift) (bytes >> shift)
-
- void CopySamplesToHardware(SoundComponentGlobalsPtr globals, SoundComponentDataPtr siftPtr) {
- long samplesToCopy, bytesToCopy, bytesLeft;
- IOBufferPtr currentBuffer;
- short sourceShift, destShift;
-
- #if DEBUG
- DebugStr ("\pIn CopySamplesToHardware");
- #endif
-
- sourceShift = 0;
- if (siftPtr->numChannels == 2) {
- sourceShift++;
- }
- if (siftPtr->sampleSize == 16) {
- sourceShift++;
- }
-
- destShift = 0;
- if (globals->thisSifter.numChannels == 2) {
- destShift++;
- }
- if (globals->thisSifter.sampleSize == 16) {
- destShift++;
- }
-
- samplesToCopy = siftPtr->sampleCount; // don't copy more than hardware buffer has
- if (samplesToCopy > kHardwareBufferSize) {
- samplesToCopy = kHardwareBufferSize;
- }
-
- currentBuffer = &globals->ioBuffers[globals->currentIndex]; // get current i/o buffer
- if (currentBuffer->iopb.ioParam.ioResult == 0) {
- bytesToCopy = SamplesToBytes(samplesToCopy, destShift); // turn samples into bytes
- bytesLeft = globals->ioBufferSize - currentBuffer->byteCount; // calc how much is left in i/o buffer
-
- if (bytesToCopy > bytesLeft) { // limit to amount we have left in buffer
- bytesToCopy = bytesLeft;
- }
- samplesToCopy = BytesToSamples(bytesToCopy, destShift); // turn back into samples
-
- if (globals->fRefNum) { // only write out if file is open
- OutputToFile(globals, siftPtr, currentBuffer->buffer + currentBuffer->byteCount, samplesToCopy);
- }
-
- currentBuffer->byteCount += bytesToCopy; // update dest pointer
- siftPtr->buffer += SamplesToBytes(samplesToCopy, sourceShift); // update source pointer
- siftPtr->sampleCount -= samplesToCopy; // subtract amount copied from source
-
- if (currentBuffer->byteCount == globals->ioBufferSize) { // current buffer is full - write it out
- if (globals->fRefNum) { // only write out if file is open
- currentBuffer->iopb.ioParam.ioReqCount = currentBuffer->byteCount; // write this many bytes out
- currentBuffer->iopb.ioParam.ioPosOffset = 0; // offset from current position
-
- #ifdef FakeInterrupts
- PBWriteSync(¤tBuffer->iopb); // write out the data synchronously
- #else
- PBWriteAsync(¤tBuffer->iopb); // start the asynch write
- #endif
- }
-
- currentBuffer->byteCount = 0; // buffer will be empty next time we use it
- globals->currentIndex ^= 1; // switch to other buffer
- }
- } else { // oh, oh, write is still in progress
- siftPtr->buffer += SamplesToBytes(samplesToCopy, sourceShift); // update source pointer
- siftPtr->sampleCount -= samplesToCopy; // subtract amount copied from source and throw these bytes away!
- }
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Slam the file.
-
- void OutputToFile(SoundComponentGlobalsPtr globals, SoundComponentDataPtr siftPtr, void *dest, short sampleCount) {
- short i;
-
- #if DEBUG
- DebugStr ("\pIn OutputToFile");
- #endif
-
- if (siftPtr->sampleSize == 8) {
- Byte *sp = siftPtr->buffer;
- Byte *dp = dest;
-
- if (siftPtr->numChannels == 1) {
- if (globals->thisSifter.numChannels == 1) {
- for (i = sampleCount - 1; i >= 0; --i) {
- *dp++ = *sp++ ^ 0x80;
- }
- } else {
- for (i = sampleCount - 1; i >= 0; --i) {
- *dp++ = *sp ^ 0x80;
- *dp++ = *sp++ ^ 0x80;
- }
- }
- } else {
- for (i = sampleCount - 1; i >= 0; --i) {
- *dp++ = *sp++ ^ 0x80;
- *dp++ = *sp++ ^ 0x80;
- }
- }
- } else {
- short *sp = (short *) siftPtr->buffer;
- short *dp = dest;
-
- if (siftPtr->numChannels == 1) {
- for (i = sampleCount - 1; i >= 0; --i) {
- *dp++ = *sp++;
- }
- } else {
- for (i = sampleCount - 1; i >= 0; --i) {
- *dp++ = *sp++;
- *dp++ = *sp++;
- }
- }
- }
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Fake interrupt routine used when running Think C to avoid the time manager.
-
- #ifdef FakeInterrupts
- Boolean FakeInterrupt(void) {
- SoundComponentGlobalsPtr globals = gGlobals; // get our globals
-
- #if DEBUG
- DebugStr ("\pIn FakeInterrupt");
- #endif
-
- if (globals->hardwareOn) {
- if (MicroSeconds() >= globals->nextTime) {
- globals->nextTime = MicroSeconds();
- InterruptRoutine(globals);
- globals->nextTime += globals->interruptInterval;
- }
- }
-
- return (globals->hardwareOn);
- }
- #else
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // Entry point for the time manager task interrupt routine
-
- //void TMInterrupt(void)
- #if !GENERATINGPOWERPC
- void TMInterrupt(myTMTaskPtr taskPtr:__a1)
- #else
- void TMInterrupt(myTMTaskPtr taskPtr)
- #endif
- {
- #if DEBUG
- DebugStr ("\pIn TMInterrupt");
- #endif
-
- //This next line needed only in Think C, not MetroWerks
- //myTMTaskPtr taskPtr = (myTMTaskPtr) GetRegisterA1(); // get poiner to time manager param block
-
- InterruptRoutine(taskPtr->globals); // call interrupt routine with globals
- }
- #endif
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // This routine is called every hardware interrupt to fill the hardware
- // with audio data. First it should suspend interrupts so it will not
- // be interrupted again (this example just queues up the next interrupt).
- // Then it should get more data from the source mixer, and copy the data
- // to the hardware. In the way out, if all data was copied, try to get
- // some more so it will be available next time.
-
- void InterruptRoutine(SoundComponentGlobalsPtr globals) {
- SoundComponentDataPtr siftPtr;
-
- #if DEBUG
- DebugStr ("\pIn InterruptRoutine");
- #endif
-
- // SuspendHardware(globals); // suspend interrupt while we are processing
- ResumeHardware(globals); // queue next interrupt while we are processing
-
- siftPtr = GetMoreSource(globals); // get source from mixer
- if (siftPtr != nil) {
- CopySamplesToHardware(globals, siftPtr); // fullfill hardware request
-
- if (siftPtr->sampleCount == 0) { // exhausted the source
- siftPtr = GetMoreSource(globals); // get more for next time
- }
- // ResumeHardware(globals); // resume interrupts
- } else { // no more source
- StopHardware(globals); // turn hardware off
- }
-
- return;
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // This routine returns the component data pointer to your mixer source. If there
- // is no source or it is empty, it will call down the chain to fill it up.
-
- SoundComponentDataPtr GetMoreSource(SoundComponentGlobalsPtr globals) {
- ComponentResult result;
- SoundComponentDataPtr siftPtr = globals->sourceDataPtr;
-
- #if DEBUG
- DebugStr ("\pIn GetMoreSource");
- #endif
-
- if ((siftPtr == nil) || (siftPtr->sampleCount == 0)) { // no data - better get some
- result = SoundComponentGetSourceData(globals->sourceComponent, &globals->sourceDataPtr);
- siftPtr = globals->sourceDataPtr;
-
- if ((result != noErr) || // error getting data
- (siftPtr == nil) || // source has no data pointer to return
- (siftPtr->sampleCount == 0)) { // source has no more data
- #if DEBUG
- DebugStr ("\p we have no more data");
- #endif
- siftPtr = nil;
- }
- }
-
- return (siftPtr); // return pointer to source
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // This routine initializes the output file and sets up the i/o param block
- // used to write the data to disk.
-
- OSErr SetupOutputFile(SoundComponentGlobalsPtr globals) {
- FSSpec fspec;
- ParmBlkPtr iopb;
- int i, j;
- char *sp;
- IOBufferPtr ioBuffer;
- OSErr err;
-
- #if DEBUG
- DebugStr ("\pIn SetupOutputFile");
- #endif
-
- err = FSMakeFSSpec(0, 0, kSndFileName, &fspec); // make the FS spec
-
- if (err == noErr) { // file exists
- err = FSpDelete(&fspec); // delete it
- if (err != noErr) {
- DebugStr("\pCould not delete file");
- }
- } else if (err != fnfErr) {
- DebugStr("\pCould not make FSSpec");
- } else {
- err = noErr; // file-not-found is not a real error since we're creating the file
- }
-
- if (err == noErr) {
- err = FSpCreate(&fspec, kCreator, kFileType, smSystemScript); // create file
- if (err != noErr) {
- DebugStr("\pCould not create file");
- }
- }
-
- if (err == noErr) {
- err = FSpOpenDF(&fspec, fsRdWrPerm, &globals->fRefNum); // open file
-
- if (err != noErr) {
- DebugStr("\pCould not open file");
- }
- }
-
- if (err == noErr) {
- err = SetupAIFFHeader(globals->fRefNum, globals->thisSifter.numChannels, globals->thisSifter.sampleRate,
- globals->thisSifter.sampleSize, 'NONE', 0, 0);
- if (err != noErr) {
- DebugStr("\pError in SetupAIFFHeader");
- }
- }
-
- if (err == noErr) {
- err = GetFPos(globals->fRefNum, &globals->headerLen); // get length of AIFF header
- if (err != noErr) {
- DebugStr("\pCould not get file position");
- }
- }
-
- if (err == noErr) {
- for (i = 0; i < 2; ++i) { // loop over both parameter blocks
- ioBuffer = &globals->ioBuffers[i];
-
- // get some memory for i/o buffers
- ioBuffer->bufferHandle = NewHandleLockClear(globals->ioBufferSize, globals->inSystemHeap);
- if (ioBuffer->bufferHandle == nil) {
- err = MemError();
- DebugStr("\pCould not get NewHandleLockClear");
- break; // get out of for loop with error
- }
-
- ioBuffer->buffer = *ioBuffer->bufferHandle; // get pointer to buffer
-
- iopb = &ioBuffer->iopb; // get pointer to param block
-
- sp = (char *) iopb;
- for (j = sizeof(ParamBlockRec) - 1; j >= 0; --j) { // zero-out the param block
- *sp++ = 0;
- }
-
- /* fill up the param block with the fields that never change after this. Note that
- fields that are set to zero are commented out since we just zeroed things above. */
-
- iopb->ioParam.ioRefNum = globals->fRefNum; // refnum of file to write to
- // iopb->ioParam.ioCompletion = nil; // no completion routine
- // iopb->ioParam.ioReqCount = 0; // no request yet
- iopb->ioParam.ioBuffer = ioBuffer->buffer; // buffer to write to
- iopb->ioParam.ioPosMode = fsAtMark | fsNoCache; // write from current position w/o cache
- // iopb->ioParam.ioPosOffset = 0; // no offset yet
- }
- }
-
- if (err != noErr) {
- if (globals->fRefNum) {
- FSClose(globals->fRefNum);
- }
-
- DisposeHandle(globals->ioBuffers[0].bufferHandle); // dispose of buffers
- DisposeHandle(globals->ioBuffers[1].bufferHandle);
- }
-
- #if DEBUG
- if (err != noErr) {
- DebugStr ("\pGot an error in SetupOutputFile");
- }
- #endif
-
- return (err);
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // This routine makes sure all asynchronous i/o is complete, writes out any
- // remaining data, updates the AIFF header and closes the file.
-
- OSErr CloseOutputFile(SoundComponentGlobalsPtr globals) {
- long filePos, bytesWritten;
- IOBufferPtr currentBuffer;
- OSErr err;
-
- #if DEBUG
- DebugStr ("\pIn CloseOutputFile");
- #endif
-
- while ((globals->ioBuffers[globals->currentIndex].iopb.ioParam.ioResult > 0) || // wait for PBWrite to complete
- (globals->ioBuffers[globals->currentIndex^1].iopb.ioParam.ioResult > 0)) { // for both buffers
- ;
- }
-
- currentBuffer = &globals->ioBuffers[globals->currentIndex]; // get current i/o buffer
-
- if (currentBuffer->byteCount != 0) { // still some data to write out
- currentBuffer->iopb.ioParam.ioReqCount = currentBuffer->byteCount; // write this many bytes out
- currentBuffer->iopb.ioParam.ioPosOffset = 0; // offset from current position
-
- PBWriteSync(¤tBuffer->iopb); // write this buffer synchronously
- }
-
- err = GetFPos(globals->fRefNum, &filePos); // get current file position
- if (err != noErr) {
- DebugStr("\pCould not get file position");
- }
-
- if (err == noErr) {
- bytesWritten = filePos - globals->headerLen; // calc no. bytes written to file
- filePos = ++filePos & ~1; // make sure file length is a word-aligned
-
- err = SetEOF(globals->fRefNum, filePos); // set current file position to EOF
- if (err != noErr) {
- DebugStr("\pCould not set EOF");
- }
- }
-
- if (err == noErr) {
- err = SetFPos(globals->fRefNum, fsFromStart, 0); // rewind file to beginning
- if (err != noErr) {
- DebugStr("\pCould not set file position");
- }
- }
-
- if (err == noErr) {
- err = SetupAIFFHeader(globals->fRefNum, globals->thisSifter.numChannels, globals->thisSifter.sampleRate,
- globals->thisSifter.sampleSize, 'NONE', bytesWritten, 0);
- if (err != noErr) {
- DebugStr("\pError in SetupAIFFHeader");
- }
- }
-
- FSClose(globals->fRefNum); // close output file
- globals->fRefNum = 0;
-
- DisposeHandle(globals->ioBuffers[0].bufferHandle); // dispose of buffers
- DisposeHandle(globals->ioBuffers[1].bufferHandle);
-
- #if DEBUG
- if (err != noErr) {
- DebugStr ("\pGot an error in CloseOutputFile");
- }
- #endif
-
- return (err);
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // This routine creates a locked handle in the requested heap.
-
- Handle NewHandleLockClear(long len, Boolean inSystemHeap) { // allocate a new handle, lock it down and clear it
- Handle h;
-
- #if FULLDEBUG
- DebugStr ("\pIn NewHandleLockClear");
- #endif
-
- if (inSystemHeap) { // we are loaded into the system heap
- ReserveMemSys(len); // create it low down in system heap
- h = NewHandleSysClear(len);
- } else { // we are loaded into the app heap
- h = NewHandleClear(len); // create our memory there and move it out of the way
- if (h != nil) {
- MoveHHi(h);
- }
- }
-
- if (h != nil) {
- HLock(h); // lock it down
- }
-
- return (h);
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // This routine gets the hardware globals out of the refCon or creates them
-
- HardwareGlobalsPtr GetHardwareGlobals(ComponentInstance self, Boolean inSystemHeap) {
- HardwareGlobalsPtr hwGlobals;
- Handle h, componentName;
- UnsignedFixed *lp;
- short *sp, i;
- ComponentDescription componentDesc;
- OSErr err;
-
- #if DEBUG
- DebugStr ("\pIn GetHardwareGlobals");
- #endif
-
- hwGlobals = (HardwareGlobalsPtr) GetComponentRefcon((Component) self);
- if (hwGlobals == nil) { //have to set up the hardware globals
- componentName = NewHandle(0);
- if (componentName != nil) {
- err = GetComponentInfo((Component) self, &componentDesc, componentName, nil, nil);
- if (err == noErr) {
- h = NewHandleLockClear(sizeof(HardwareGlobals), inSystemHeap);
- if (h != nil) {
- HUnlock(h);
- HLock(componentName);
- err = GetSoundPreference(componentDesc.componentSubType, (StringPtr) *componentName, h);
- if (err == noErr) {
- DisposeHandle(componentName);
- HLock(h);
- hwGlobals = (HardwareGlobalsPtr) *h;
- SetComponentRefcon((Component) self, (long) hwGlobals);
- } else {
- DisposeHandle(h); //GetSoundPreference failed
- DisposeHandle(componentName);
- }
- } else { //NewHandleLockClear failed
- DisposeHandle(componentName);
- }
- } else { //GetComponentInfo failed
- DisposeHandle(componentName);
- }
-
- if (h == nil || err != noErr) { //failed to get globals, try to make them
- h = NewHandleLockClear(sizeof(HardwareGlobals), inSystemHeap);
- if (h != nil) {
- hwGlobals = (HardwareGlobalsPtr) *h;
-
- SetComponentRefcon((Component) self, (long) hwGlobals);
-
- /* Setup sample sizes */
-
- sp = hwGlobals->sampleSizesActive;
- for (i = kSampleSizesCount - 1; i >= 0; --i) {
- *sp++ = 1;
- }
- sp = hwGlobals->sampleSizes;
- *sp++ = 8; // 8-bit
- *sp++ = 16; // 16-bit
-
- /* Setup sample rates */
-
- sp = hwGlobals->sampleRatesActive;
- for (i = kSampleRatesCount - 1; i >= 0; --i) {
- *sp++ = 1;
- }
- lp = hwGlobals->sampleRates;
- *lp++ = rate44khz; // 44.100 kHz
- *lp++ = rate22050hz; // 22.050 kHz
- *lp++ = rate11025hz; // 11.025 kHz
- *lp++ = rate22khz; // 22.254 kHz
- *lp++ = rate11khz; // 11.127 kHz
- *lp++ = 0x1F400000; // 8.000 kHz
-
- hwGlobals->sampleRateMin = 0x00010000; // sample rate min
- hwGlobals->sampleRateMax = 0xAC440000; // sample rate max
-
- /* Setup channels */
-
- sp = hwGlobals->channelsActive;
- for (i = kChannelsCount - 1; i >= 0; --i) {
- *sp++ = 1;
- }
- sp = hwGlobals->channels;
- *sp++ = 1; // mono
- *sp++ = 2; // stereo
-
- /* Initial hardware settings */
-
- hwGlobals->volume = ((long)256 << 16) | 256;
- hwGlobals->sampleSize = 16;
- hwGlobals->numChannels = 2;
- hwGlobals->sampleRate = rate44khz;
- hwGlobals->bufferSize = 1024;
- hwGlobals->supportsRateRange = false;
- hwGlobals->outputToFile = true;
- hwGlobals->outputToHardware = false;
- hwGlobals->dirty = true;
- } else {
- hwGlobals = nil;
- }
- }
- } else { //NewHandle(0) failed, no memory for globals
- hwGlobals = nil;
- }
- }
-
- return (hwGlobals);
- }
-
- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // This routine saves the hardware globals in the refCon
-
- OSErr SaveHardwareGlobals(ComponentInstance self, HardwareGlobalsPtr hwGlobals) {
- Handle h,
- componentName;
- ComponentDescription componentDesc;
- OSErr err = noErr;
-
- #if DEBUG
- DebugStr ("\pIn SaveHardwareGlobals");
- #endif
-
- if (hwGlobals != nil) {
- if (hwGlobals->dirty == true) {
- componentName = NewHandle(0);
- if (componentName != nil) {
- err = GetComponentInfo((Component) self, &componentDesc, componentName, nil, nil);
- if (err != noErr) {
- h = RecoverHandle((Ptr) hwGlobals);
- err = MemError();
- if (err != noErr) {
- HLock(componentName);
- hwGlobals->dirty = false;
- err = SetSoundPreference(componentDesc.componentSubType, (StringPtr) *componentName, h);
- } else {
- DisposeHandle(componentName);
- }
- } else {
- DisposeHandle(componentName);
- }
- } else {
- err = MemError();
- }
- }
- } else {
- err = notEnoughHardwareErr;
- }
-
- #if DEBUG
- if (err != noErr) {
- DebugStr ("\pGot an error in SaveHardwareGlobals");
- }
- #endif
-
- return (err);
- }
-
- #if GENERATINGPOWERPC
- //for 68K the macro we are using only returns a long, so the PPC version
- //will just return the lo part of the number to be consistent
- unsigned long MicroSeconds(void) {
- UnsignedWide microTickCount;
-
- #if FULLDEBUG
- DebugStr ("\pIn MicroSeconds");
- #endif
-
- Microseconds (µTickCount);
- return (microTickCount.lo);
- }
- #endif
-